package com.fox.lock.task;

import com.fox.lock.DistributedLockService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author: [wujie]
 * @createTime: [2019/6/22 16:08]
 * @description: 任务线程的续时线程 在任务线程没执行完 或者设置的超时时间没到的时候会一直运行
 */
public class ExpireThread implements Runnable {
    private static final Logger logger = LoggerFactory.getLogger(ExpireThread.class);
    private volatile AbstractSingleTimerTask singleTimerTask;
    private volatile DistributedLockService distributedLockService;
    private volatile long expireMills;
    private volatile long periodExpireMills;
    private volatile String lockName;
    private volatile String requestId;

    /**
     * @param singleTimerTask        引用
     * @param distributedLockService 分布式锁
     * @param lockName               锁名
     * @param requestId              业务id
     * @param expireMills            超时总时间 （每次续时 超时总时间=超时总时间-续时时间）
     * @param periodExpireMills      续时时间
     */
    public void init(AbstractSingleTimerTask singleTimerTask, DistributedLockService distributedLockService, String lockName
            , String requestId, long expireMills, long periodExpireMills) {
        this.singleTimerTask = singleTimerTask;
        this.distributedLockService = distributedLockService;
        this.expireMills = expireMills;
        this.periodExpireMills = periodExpireMills;
        this.lockName = lockName;
        this.requestId = requestId;
    }

    @Override
    public void run() {
        try {
            //如果已经超时并且任务已经停止运行 停止续时
            if (expireMills <= 0 && !singleTimerTask.isSingleTimerTaskAlive()) {
                logger.debug("[{}]-[{}]续时线程停止运行", lockName, requestId);
                singleTimerTask.stopExpireThread();
                //直接释放锁
                distributedLockService.tryRelease(lockName, requestId);
            } else {
                logger.debug("[{}]-[{}]续时线程续时[{}ms]剩余时间[{}ms]", lockName, requestId, periodExpireMills, expireMills);
                //续时操作 每次续 periodExpireMills ,expireMills是总超时时间
                expireMills = expireMills - periodExpireMills;
                long time = distributedLockService.addExpire(lockName, requestId, periodExpireMills);
                //重置成-1防止溢出
                expireMills=Math.max(expireMills,-1);
                //补时差(请求与真正续时的时差会导致redis里锁的时间越来越小)
                if (time < periodExpireMills && (singleTimerTask.isSingleTimerTaskAlive() || expireMills > 0)) {
                    time = distributedLockService.addExpire(lockName, requestId, periodExpireMills - time + 500);
                }
                logger.debug("[{}]-[{}]redis中剩余时间[{}ms]", lockName, requestId, time);
                //redis锁已经不存在 停止任务线程
                if (time == 0) {
                    singleTimerTask.stopExpireThread();
                    singleTimerTask.stopSingleTimerTask();
                }
            }
        } catch (Exception e) {
            //捕获运行时异常 （一般是redis连接不上报错）出异常的时候停止运行任务
            singleTimerTask.stopExpireThread();
            singleTimerTask.stopSingleTimerTask();
        }
    }


}
